package okl.lab.components
{

	import flash.events.Event;
	
	import mx.collections.ArrayCollection;
	import mx.collections.IList;
	import mx.collections.ListCollectionView;
	import mx.collections.Sort;
	import mx.collections.SortField;
	import mx.core.ClassFactory;
	import mx.states.OverrideBase;
	
	import okl.lab.components.interfaces.IFilterAndSortList;
	import okl.lab.components.skins.FilterAndSortListDefaultSkin;
	
	import spark.components.ComboBox;
	import spark.components.DropDownList;
	import spark.components.List;
	import spark.components.SkinnableContainer;
	import spark.components.TextInput;
	import spark.events.TextOperationEvent;
	import spark.skins.spark.DefaultItemRenderer;
	
	//=====================EVENTS=====================================//	
	/**
	 *  Dispatched when filter changes
	 *
	 *  @eventType change
	 */
	[Event(name="change", type="flash.events.Event")]
	[DefaultTriggerEvent("change")]	
	/**
	 *  Dispatched when the <code>dataProvider</code> property changes.
	 *
	 *  @eventType dataChange
	 */
	[Event(name="dataChange", type="flash.events.Event")]

	/**
	 *  A factory that represents the <code>itemRender</code> class for filtered list
	 */	
	[Style(name="itemRenderer", type="mx.core.IFactory", inherit="no")]
	/**
	 *  Component for filter and display colllection.
	 *  Filtering by <code>searchTerm</code> and sorting using <code>dataSortFields</code>
	 *	@see okl.lab.components.interfaces.IFilterAndSortList
	 */
	public class FilterAndSortList extends SkinnableContainer implements IFilterAndSortList
	{
		public function FilterAndSortList()
		{
			super();
			setStyle("skinClass", FilterAndSortListDefaultSkin);
		}
		
		//{region IFilterAndSortList
		private var _dataProvider:ArrayCollection;
		[Bindable(event="dataChange")]public function get dataProvider():ArrayCollection
		{
			return _dataProvider;
		}
		
		public function set dataProvider(value:ArrayCollection):void
		{			
			_dataProvider=value;
			dispatchEvent(new Event("dataChange"));
			invalidateData();			
		}
		
		private var __dataFilteredDirty:Boolean;
		private var _dataFiltered:ArrayCollection;
		[Bindable(event="change")]public function get dataFiltered():ArrayCollection
		{
			return _dataFiltered;
		}
		
		private var __searchTermDirty:Boolean;
		private var _searchTerm:String;
		/**
		 * Search term can be assigned or entered by user
		 */
		[Bindable(event="change")]public function get searchTerm():String
		{
			return _searchTerm;
		}
		
		public function set searchTerm(value:String):void
		{
			_searchTerm=value;
			__searchTermDirty=true;
			invalidateData();
		}
		
		private var _dataSortFields:Array;
		/**
		 * @param value array of property names used for sorting
		 */
		public function set dataSortFields(value:Array):void{
			_dataSortFields=value;
			invalidateData();		
		}
		
		private var _dataFilterField:String;
		public function set dataFilterField(value:String):void{
			_dataFilterField=value;
			invalidateData();		
		}
		//}endregion
		
		//{region LIST_mediation
		private var __labelFieldDirty:Boolean;
		private var _labelField:String;
		/**
		 *
		 */
		public function set labelField(value:String):void{
			_labelField=value;
			__labelFieldDirty=true;
			invalidateProperties();
		}
		private var __labelFunctionDirty:Boolean;
		private var _labelFunction:Function;
		public function set labelFunction(value:Function):void{
			_labelFunction=value;
			__labelFunctionDirty=true;
			invalidateProperties();
		}
		//}endregion		
	
		//{region SkinParts
		/**
		 * Search term input. Use <code>searchTerm</code> to set it</cod>
		 */
		[SkinPart(required="true")]public var tiSearchTerm:TextInput;
		/**
		 * Filtered and sorted list ui
		 */
		[SkinPart(required="true")]public var liDataFiltered:List;
		
		override protected function partAdded(partName:String, instance:Object):void{
			super.partAdded(partName, instance);
			if(instance==tiSearchTerm){
				tiSearchTerm.addEventListener(TextOperationEvent.CHANGE, onSearchTermTextChange);
			}else if(instance==liDataFiltered){}
		}
		
		override protected function partRemoved(partName:String, instance:Object):void{
			super.partRemoved(partName, instance);
			if(instance==tiSearchTerm){
				tiSearchTerm.removeEventListener(TextOperationEvent.CHANGE, onSearchTermTextChange);
			}		
		}
		//}endregion
		

		//{region LIFE_CYCLE
		override protected function commitProperties():void{
			super.commitProperties();
			if(__labelFieldDirty){
				liDataFiltered.labelField=_labelField;
				__labelFieldDirty=false;
			}
			
			if(__labelFunctionDirty){
				liDataFiltered.labelFunction=_labelFunction;
				__labelFunctionDirty=false;
			}
			
			if(__dataFilteredDirty){
				liDataFiltered.dataProvider = dataFiltered;
				__dataFilteredDirty=false;
			}
			
			if(__searchTermDirty){
				tiSearchTerm.text=searchTerm;
				__searchTermDirty=false;
			}
			
			if(__itemRendererDirty){
				var itemRenderer:Class =getStyle("itemRenderer") || DefaultItemRenderer;
				liDataFiltered.itemRenderer = new ClassFactory(itemRenderer);
				__itemRendererDirty=false;
			}
			
		}
		
		private var __itemRendererDirty:Boolean=true;/*invalidate on first pass*/
		override public function styleChanged(styleProp:String):void{			
			if(styleProp=="itemRenderer"){
				__itemRendererDirty=true;
				invalidateProperties();
				
			}			
			super.styleChanged(styleProp);
		}
		
		/**
		 *Invalidating <code>dataFiltered</code>
		 */
		private function invalidateData(event:Event=null):void{
			var newData:ArrayCollection=null;
			if(dataProvider!=null){
				newData= new ArrayCollection(dataProvider.source);
				newData.filterFunction = dataFilter;				
				if(_dataSortFields){	
					var sort:Sort = new Sort();
					var fields:Array = new Array();
					for(var i:uint; i<_dataSortFields.length; i++){
						fields.push(new SortField(_dataSortFields[i], true));
					}
					sort.fields = fields;
					newData.sort = sort;			
				}			
				newData.refresh();	
			}
			
			
			_dataFiltered=newData;
			__dataFilteredDirty=true;			
			dispatchEvent(new Event("change"));
			
			invalidateProperties();
		}
		//}endregion
		
		//{region INTER_LOGIC
		protected function onSearchTermTextChange(event:TextOperationEvent):void{
			_searchTerm=tiSearchTerm.text;
			invalidateData();
		}
		
		private function dataFilter(value:Object):Boolean{
			if(searchTerm=="")return false;
			if(!value.hasOwnProperty(_dataFilterField))return false;
			var targetValue:String = value[_dataFilterField];
			return targetValue.indexOf(this.searchTerm) !=-1;	
		}
		//}endregion	

	}
}